//
//  OosAbstractParser.m
//  oos4ios
//
//  Created by Pablo Gonzalez on 5/12/11.
//  Copyright 2011 11870.com. All rights reserved.
//

#import "OosAbstractParser.h"
#import "../Persistence/OosManagedContext.h"
#import "../Persistence/OosManagedObjectMover.h"

/**
 
 Gatekeeper of the ManagedObjectContext. It is used to transfer the souls of 
 objects lost in remote threads into the main thread so they can be put 
 to good use there. The two coins needed are the object itself and the callback 
 that will handle the object upon arrival
 
 */
@interface ContextCharon : NSObject {
    
    NSPersistentStoreCoordinator *mCoordinator;
    OosManagedContext *mThreadContext;
    OosManagedContext *mMainContext;
    id mResult;
    id<IOosParserCallback> mCallback;
    
}

@property (nonatomic, retain) id result;
@property (nonatomic, retain) id<IOosParserCallback> callback;

- (void) pass;

@end

@implementation ContextCharon

@synthesize result = mResult;
@synthesize callback = mCallback;

- (void)pass {  
    
    mThreadContext = [OosManagedContext context];
    mCoordinator = [mThreadContext persistentStoreCoordinator];
    
    // lock the store we share with main thread's context  
    [mCoordinator lock];  
    
    // save any changes, observe it so we can trigger merge with the actual context  
    @try {  
        [mThreadContext processPendingChanges];  
    }  
    @catch (NSException * e) {  
        NSLog(@"%@", [e description]);  
        [mCoordinator unlock];  
    }  
    @finally {  
        // pass  
    }  
    
    NSNotificationCenter *dnc = [NSNotificationCenter defaultCenter];  
    [dnc addObserver: self 
            selector: @selector(threadControllerContextDidSave:) 
                name: NSManagedObjectContextDidSaveNotification 
              object: mThreadContext];  
    @try {  
        NSError *error;  
        if (![mThreadContext save:&error]) {  
            NSLog(@"%@", [error localizedDescription]);  
            [mCoordinator unlock];  
            [self performSelectorOnMainThread:@selector(handleSaveError:) withObject:nil waitUntilDone:NO];  
        }  
    } @catch (NSException *e) {  
        NSLog(@"%@", [e description]);  
        [mCoordinator unlock];  
    } @finally {  
        // pass  
    }  
    [dnc removeObserver:self name:NSManagedObjectContextDidSaveNotification object:mThreadContext]; 
}  

// Merging changes causes the fetched results controller to update its results  
- (void)threadControllerContextDidSave:(NSNotification*)saveNotification {  
    // need to unlock before we let main thread merge  
    [mCoordinator unlock];  
    [self performSelectorOnMainThread:@selector(mergeToMainContext:) withObject:saveNotification waitUntilDone:YES];  
}  

- (void)mergeToMainContext:(NSNotification*)saveNotification {  
    NSError *error= nil;  
    mMainContext = [OosManagedContext mainContext];
    [mMainContext mergeChangesFromContextDidSaveNotification:saveNotification];  
    [mMainContext save:&error];
    id result = nil;
    if (!error) { 
        result = [OosManagedContext moveObjectToMainContext:self.result];
    } else {
        result = error;
        NSLog(@"%@", [error localizedDescription]);
    }
    
    [mCallback received:result];
}  

@end

@implementation OosAbstractParser

- (void) reportResult: (id) result 
         withCallback: (id<IOosParserCallback>) callback
{
    if (![NSThread isMainThread]) {
        result = [OosManagedObjectMover moveObjectToMaincontext:result];
        NSObject *objectCallback = (NSObject *) callback;
        [objectCallback performSelectorOnMainThread: @selector(received:) 
                                         withObject: result 
                                      waitUntilDone: NO];
    } else {
        [callback received:result];
    }
}

static NSDateFormatter *jsonFormatter;
static NSDateFormatter *atomFormatter;

+ (NSDateFormatter *)jsonFormatter
{
    if (!jsonFormatter) {
        jsonFormatter = [[NSDateFormatter alloc] init];
        [jsonFormatter setDateFormat:@"eee MMM d HH:mm:ss zzzz yyyy"];
    }
    return jsonFormatter;
}

+ (NSDateFormatter *)atomFormatter
{
    if (!atomFormatter) {
        atomFormatter = [[NSDateFormatter alloc] init];
        [atomFormatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"];
    }
    return atomFormatter;
}

@end
